Skip to content

release: patch post-merge review fixes for v1.2.4 - #356

Merged
ndycode merged 6 commits into
mainfrom
release/post-merge-review-fixes-1.2.4
Apr 5, 2026
Merged

release: patch post-merge review fixes for v1.2.4#356
ndycode merged 6 commits into
mainfrom
release/post-merge-review-fixes-1.2.4

Conversation

@ndycode

@ndycode ndycode commented Apr 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • ship the post-merge v1.2.4 follow-up fixes for #355 on top of current main

What Changed

  • made the shadow-home rename retry regression deterministic by replacing the timed mutator with a retry-marker barrier
  • only log flagged backup recovery as successful after the recovered storage is actually persisted
  • replaced the unified-settings invalid-root string check with a dedicated InvalidSettingsRecordError
  • kept the earlier scoped fixes for malformed unified settings recovery, flagged-storage read retries, non-429 capability failure accounting, and shadow-home sync-back retry handling

Validation

  • npm run clean:repo:check
  • npm run lint
  • npm run typecheck
  • npm run build
  • npm test -- --reporter=dot

note: greptile review for oc-chatgpt-multi-auth. cite files like lib/foo.ts:123. confirm regression tests + windows concurrency/token redaction coverage.

Greptile Summary

this pr ships the post-merge follow-up fixes for v1.2.4 on top of main. the three headline changes are: (1) the success logInfo for flagged backup recovery is now gated behind a successful persistRecoveredBackup call rather than firing unconditionally; (2) invalid-root detection in unified-settings was promoted from an ad-hoc string/instanceof check to a dedicated InvalidSettingsRecordError class with an isInvalidSettingsRecordError helper; and (3) the shadow-home rename retry was made deterministic by replacing the timed mutator with a retry-marker barrier (writeShadowHomeCleanupRetryMarker) plus a preflight destination-snapshot check (ensureShadowHomeDestinationMatchesSnapshot).

  • flagged-storage-io.ts — logInfo ordering fix is correct; the persistRecoveredBackup call is now required before success is declared. note that for empty-account backups (recovered.accounts.length === 0) the persist block is skipped and logInfo still fires with accounts: 0, which is a minor log-semantics rough edge.
  • unified-settings.tsInvalidSettingsRecordError cleanly separates corruption (silenced in backup readers) from transient FS lock errors (rethrown for callers to retry). the async write queue serializes in-process writes; sync callers (saveUnifiedPluginConfigSync) bypass the queue and can race with async writers — this is a known design trade-off and is documented in JSDoc. windows path and locking caveats are correctly noted.
  • scripts/codex.js — the EEXIST code is used as a synthetic sentinel in ensureShadowHomeDestinationMatchesSnapshot to signal "destination changed during retry" — functional but unconventional since EEXIST has a standard posix meaning; could confuse someone reading logs.
  • vitest coverage is solid across all three fix areas, including persist-fail, persist-false, reset-marker race, and retry-marker observability paths.

Confidence Score: 5/5

safe to merge; all remaining findings are P2 style/logging concerns with no correctness or data-integrity impact

the three headline fixes (logInfo ordering, InvalidSettingsRecordError, shadow-home retry barrier) are all correct and well-tested. vitest coverage is comprehensive across persist-fail, persist-false, reset-marker race, transient read retry, and concurrent write scenarios. the two P2 findings (zero-account logInfo noise and EEXIST sentinel) do not affect behavior or data safety.

lib/storage/flagged-storage-io.ts lines 94-117 (logInfo for zero-account recoveries); scripts/codex.js lines 278-281 (EEXIST sentinel code)

Important Files Changed

Filename Overview
lib/storage/flagged-storage-io.ts logInfo correctly gated after persistRecoveredBackup, but still fires spuriously for zero-account backups
lib/unified-settings.ts InvalidSettingsRecordError cleanly replaces string check; isInvalidSettingsRecordError covers SyntaxError and custom type; write-queue serialization and skipBackupSnapshot flag are correct
scripts/codex.js shadow-home rename retry deterministic via retry-marker barrier and preflight snapshot check; EEXIST sentinel is functional but semantically unconventional
lib/storage/flagged-storage-file.ts readFileWithRetry with 4-attempt exponential back-off for EBUSY/EAGAIN windows lock codes; injectable sleep dep for test control
test/storage-flagged.test.ts vitest coverage for persist-fail, persist-false, transient retry, reset-marker race, and partial-delete suppression paths
test/unified-settings.test.ts covers sync/async backup fallback, EBUSY rethrow, skipBackupSnapshot, write-queue serialization, and concurrent write scenarios
test/codex-bin-wrapper.test.ts integration tests for shadow-home retry-marker observability and preflight-read busy-failure injection via env hooks
test/index.test.ts config mock stubs kept current; capability and storage mocks aligned with production exports

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[loadFlaggedAccountsState] --> B{resetMarker exists?}
    B -- yes --> Z[return empty]
    B -- no --> C[readFileWithRetry primary]
    C -- EBUSY/EAGAIN --> C
    C -- success --> D{isValidFlaggedStorageCandidate?}
    D -- no --> E[logError + loadFlaggedBackup]
    D -- yes --> F{resetMarker now?}
    F -- yes --> Z
    F -- no --> G[return loaded]
    C -- ENOENT --> H[loadFlaggedBackup]
    C -- other error --> E

    subgraph loadFlaggedBackup
        H --> I[iterate .bak .bak.1 .bak.2]
        I --> J[readFileWithRetry backup]
        J -- EBUSY/EAGAIN retry --> J
        J -- invalid --> I
        J -- valid + accounts>0 --> K[persistRecoveredBackup]
        K -- false --> Z
        K -- throws --> L[logError + return recovered]
        K -- true --> M[logInfo + return recovered]
        J -- valid + accounts=0 --> N[logInfo accounts:0 + return recovered]
    end

    H -- null --> O{legacyPath exists?}
    O -- no --> Z
    O -- yes --> P[readFileWithRetry legacy]
    P -- success --> Q[saveFlaggedAccounts + unlink + logInfo + return migrated]
    P -- error --> R[logError + return empty]
Loading

Fix All in Codex

Prompt To Fix All With AI
This is a comment left during a code review.
Path: lib/storage/flagged-storage-io.ts
Line: 94-117

Comment:
**logInfo fires for zero-account backup recoveries**

when `recovered.accounts.length === 0` the `persistRecoveredBackup` block is skipped entirely and execution falls through to the `logInfo` at line 112, emitting "Recovered flagged account storage from backup" with `accounts: 0`. this produces a misleading success signal — no accounts were actually recovered and the caller receives the same value as `empty`. the PR's stated goal was to only log success after the storage is actually persisted; guarding the logInfo with `recovered.accounts.length > 0` would make the semantics consistent.

```suggestion
				if (recovered.accounts.length > 0) {
					params.logInfo("Recovered flagged account storage from backup", {
						from: backupPath,
						to: params.path,
						accounts: recovered.accounts.length,
					});
				}
				return recovered;
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: scripts/codex.js
Line: 278-281

Comment:
**EEXIST used as synthetic sentinel may mislead future readers**

`EEXIST` is a standard posix error meaning "file or directory already exists." using it as a custom sentinel for "destination changed during sync-back retry" is unexpected — if this error ever surfaces in a log or a stack trace, someone debugging it will look for a file-already-exists failure rather than a state-mismatch abort. functionally fine since `EEXIST` is not in `RETRYABLE_SHADOW_HOME_CLEANUP_CODES` and the error is swallowed upstream in `syncShadowHomeStateBack`, but a more descriptive code (e.g. `"ECHANGED"`) or no code at all would be clearer.

```suggestion
		const error = new Error("shadow-home destination changed during sync-back retry");
		error.code = "ECHANGED";
		throw error;
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (6): Last reviewed commit: "test: cover flagged backup retry edge ca..." | Re-trigger Greptile

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@coderabbitai

coderabbitai Bot commented Apr 5, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

v1.2.4 updates docs and package metadata, exports and uses a flagged-storage read-with-retry helper, tightens unified-settings invalid-record handling and legacy-path logic, moves capability-policy failure recording into the streaming fallback failure block, adds shadow-home rename retry with destination snapshot checks, and adds tests for these flows.

Changes

Cohort / File(s) Summary
release metadata
README.md, docs/README.md, package.json
bumped stable release links to v1.2.4 and updated package.json version to 1.2.4.
release notes
docs/releases/v1.2.4.md
added new release page describing patch behavior, validation commands, and test results.
flagged storage retry helper
lib/storage/flagged-storage-file.ts, lib/storage/flagged-storage-io.ts
exported readFileWithRetry in lib/storage/flagged-storage-file.ts and replaced direct fs.readFile calls with readFileWithRetry(...) in lib/storage/flagged-storage-io.ts for backup, primary, and legacy reads.
streaming failover capability recording
index.ts
moved capabilityPolicyStore.recordFailure(...) into the fallback failure block so capability failures are recorded immediately when accountManager.recordFailure(...) runs.
unified settings error handling & config path logic
lib/unified-settings.ts, lib/config.ts
added InvalidSettingsRecordError and isInvalidSettingsRecordError; changed parse/read behavior so invalid-root unified JSON can yield { record: null, usedBackup: false }; simplified legacyPath computation in savePluginConfig to depend on unifiedConfig === null.
shadow-home rename retry & snapshot validation
scripts/codex.js
added simulated preflight read failure hook, renameFileWithRetry(...) with backoff and destination snapshot checks, ensureShadowHomeDestinationMatchesSnapshot(...), and wired syncShadowHomeStateFile(...) to use the retrying rename.
tests (retry, fallback, and sync-back scenarios)
test/codex-bin-wrapper.test.ts, test/config-save.test.ts, test/index.test.ts, test/storage-flagged.test.ts, test/unified-settings.test.ts, test/dashboard-settings.test.ts, test/codex-manager-cli.test.ts
added and adjusted tests to exercise transient EBUSY/EPERM retries, config fallback preservation when unified settings are invalid, capability-policy recording on fallback errors, and rename-retry concurrency scenarios.

Sequence Diagram(s)

sequenceDiagram
    participant client as client
    participant flagged as lib/storage/flagged-storage-io
    participant retry as lib/storage/flagged-storage-file:readFileWithRetry
    participant fs as fs

    client->>flagged: loadFlaggedAccounts()
    flagged->>retry: readFileWithRetry(primaryPath)
    retry->>fs: readFile(primaryPath)
    fs-->>retry: error EBUSY
    retry->>retry: sleep/backoff (rgba(200,100,50,0.5))
    retry->>fs: readFile(primaryPath)
    fs-->>retry: success
    retry-->>flagged: file contents
    flagged->>flagged: JSON.parse/validate
    flagged-->>client: resolved flagged accounts
Loading
sequenceDiagram
    participant cli as savePluginConfig
    participant unified as lib/unified-settings
    participant fs as fs
    participant standalone as standalone config.json

    cli->>unified: savePluginConfig({ fastSession })
    unified->>fs: readFile(settings.json)
    fs-->>unified: SyntaxError (invalid JSON)
    unified->>fs: readFile(config.json)
    fs-->>unified: standalone config contents
    unified->>unified: merge standalone values + new pluginConfig
    unified->>fs: writeFile(settings.json, merged)
    fs-->>unified: success
    unified-->>cli: saved
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

notes and reviewer flags

  • inspect lib/storage/flagged-storage-file.ts:line for the exported readFileWithRetry signature and all call sites in lib/storage/flagged-storage-io.ts:line.
  • review lib/unified-settings.ts:line and lib/config.ts:line to confirm invalid unified json now yields { record: null, usedBackup: false } and that savePluginConfig preserves standalone config.json only in intended fallback paths.
  • review ordering change in index.ts:line where capabilityPolicyStore.recordFailure was moved into the fallback failure block. flag potential duplicate/missed recordings under rapid successive fallbacks.
  • inspect scripts/codex.js:line rename retry and ensureShadowHomeDestinationMatchesSnapshot for concurrency races where an external actor mutates the destination during backoff. missing regression test that simulates simultaneous external write + rename retry.
  • flag windows-specific transient locks (EBUSY/EPERM) as a ci flakiness risk. ensure tests in test/unified-settings.test.ts:line, test/storage-flagged.test.ts:line, and test/codex-bin-wrapper.test.ts:line adequately cover windows edge cases and concurrency; add coverage if gaps are found.

Suggested labels

bug

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 24.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed Title follows conventional commits format with type 'release', scope implicit, and summary within 72 chars, directly related to the v1.2.4 patch release objective.
Description check ✅ Passed PR description follows template structure with Summary, What Changed, and Validation sections completed; all required checkbox items marked; Docs/Governance and Risk sections present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/post-merge-review-fixes-1.2.4
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch release/post-merge-review-fixes-1.2.4

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/README.md`:
- Around line 26-27: Update the "previous stable" release links that currently
point to v1.2.2 so they reference v1.2.3 instead: change occurrences of
"[releases/v1.2.2.md]" and the linked label "Previous stable release notes"
entries in docs/README.md and the other README.md index entry to
"[releases/v1.2.3.md]" (and any matching label text if duplicated), ensuring
both indices that reference a previous-stable release now point to v1.2.3
instead of v1.2.2.

In `@docs/releases/v1.2.4.md`:
- Line 28: The release note line containing the exact text "Full suite passed:
`222/222` files, `3303/3303` tests" is likely outdated; verify the true number
of files and tests after the final merge (by checking CI job summary or running
the test-count script used by CI) and update that inline text to the current
counts so the release note reflects the actual post-merge totals.

In `@index.ts`:
- Around line 2195-2198: Add a deterministic vitest regression that asserts the
non-429 fallback path calls capabilityPolicyStore.recordFailure exactly once:
create a test that triggers the code path which invokes
capabilityPolicyStore.recordFailure with fallbackEntitlementAccountKey and
capabilityModelKey (the same path introduced around
capabilityPolicyStore.recordFailure in index.ts) and verify the failure counter
increments by one even under simulated concurrency (use deterministic
concurrency tools like queued promises or fake timers, avoid real secrets or
filesystem-dependent behavior); ensure the test complements existing 429
no-penalty assertions and references the logic in lib/capability-policy.ts (the
failure recording region) to guard against token-refresh/race regressions.

In `@scripts/codex.js`:
- Around line 227-252: The retry loop in renameFileWithRetry currently sleeps
and retries without re-validating the destination, widening the no-clobber race;
update renameFileWithRetry to read and compare the destination
snapshot/hash/mtime (the same validation used in syncShadowHomeStateBack) before
each retry attempt and abort (throw) if the destination has diverged from the
original validated snapshot, so transient EBUSY sleeps cannot later clobber a
changed destination; use the same comparison logic used in
syncShadowHomeStateBack and reference the original snapshot captured before
calling renameFileWithRetry, leaving maybeThrowSimulatedShadowHomeBusyError and
the existing backoff array unchanged.

In `@test/codex-bin-wrapper.test.ts`:
- Line 529: The test currently injects busy failures via
injectShadowCleanupBusyFailures() but never mutates the sync-back files during
the retry/backoff window; add a new vitest test that deterministically simulates
a concurrent external mutation of accounts.json (or .codex-global-state.json)
during the backoff between the first busy retry and the eventual rename in
scripts/codex.js (the rename/retry logic around the existing retry loop). Use
vitest fake timers or controlled promises to advance the backoff and perform the
file mutation mid-backoff so the test reproduces the delayed-clobber regression;
keep the test deterministic and use the same helpers
(injectShadowCleanupBusyFailures(), the cleanup invocation used at
test/codex-bin-wrapper.test.ts) to assert the code handles the mid-backoff
external change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 10cb7cae-eca5-4431-b658-81463e8620e7

📥 Commits

Reviewing files that changed from the base of the PR and between c1da059 and 3107259.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (17)
  • README.md
  • docs/README.md
  • docs/releases/v1.2.4.md
  • index.ts
  • lib/config.ts
  • lib/storage/flagged-storage-file.ts
  • lib/storage/flagged-storage-io.ts
  • lib/unified-settings.ts
  • package.json
  • scripts/codex.js
  • test/codex-bin-wrapper.test.ts
  • test/codex-manager-cli.test.ts
  • test/config-save.test.ts
  • test/dashboard-settings.test.ts
  • test/index.test.ts
  • test/storage-flagged.test.ts
  • test/unified-settings.test.ts
💤 Files with no reviewable changes (1)
  • test/codex-manager-cli.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (3)
docs/**

⚙️ CodeRabbit configuration file

keep README, SECURITY, and docs consistent with actual CLI flags and workflows. whenever behavior changes, require updated upgrade notes and mention new npm scripts.

Files:

  • docs/README.md
  • docs/releases/v1.2.4.md
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/codex-bin-wrapper.test.ts
  • test/unified-settings.test.ts
  • test/storage-flagged.test.ts
  • test/config-save.test.ts
  • test/dashboard-settings.test.ts
  • test/index.test.ts
lib/**

⚙️ CodeRabbit configuration file

focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.

Files:

  • lib/storage/flagged-storage-file.ts
  • lib/storage/flagged-storage-io.ts
  • lib/unified-settings.ts
  • lib/config.ts
🔇 Additional comments (10)
lib/storage/flagged-storage-file.ts (1)

11-11: looks good.

exporting the helper from lib/storage/flagged-storage-file.ts:11-28 keeps one windows read-lock retry contract, and test/storage-flagged.test.ts:632-682 already exercises the retry codes and exhaustion behavior. As per coding guidelines, lib/**: focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios.

lib/storage/flagged-storage-io.ts (1)

4-4: looks good.

routing primary, backup, and legacy reads through readFileWithRetry() at lib/storage/flagged-storage-io.ts:79-81, lib/storage/flagged-storage-io.ts:129-131, and lib/storage/flagged-storage-io.ts:162-164 keeps the windows lock handling consistent across recovery paths. the affected flows are covered by test/storage-flagged.test.ts:137-169, test/storage-flagged.test.ts:295-342, test/storage-flagged.test.ts:344-399, and test/storage-flagged.test.ts:632-682. As per coding guidelines, lib/**: focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios.

Also applies to: 79-81, 129-131, 162-164

test/storage-flagged.test.ts (1)

344-399: good regression.

test/storage-flagged.test.ts:344-399 proves the EBUSY primary read stays on the primary path and does not fall through to backup, which matches the new flow in lib/storage/flagged-storage-io.ts:128-149 on top of lib/storage/flagged-storage-file.ts:11-28. As per coding guidelines, test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior.

test/dashboard-settings.test.ts (1)

220-234: good cleanup on the fs mocks.

limiting the spy to dashboard-settings.json and asserting per-path attempt counts in test/dashboard-settings.test.ts:220-234, test/dashboard-settings.test.ts:263-314, and test/dashboard-settings.test.ts:445-464 makes the windows retry cases deterministic against lib/dashboard-settings.ts:81-114, and the finally restores prevent cross-test bleed in vitest. As per coding guidelines, test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior.

Also applies to: 263-273, 279-279, 295-306, 311-311, 445-452

README.md (1)

311-311: release-notes pointer update is clean.

line 311 correctly advances the current stable release notes pointer to v1.2.4. ref: test/unified-settings.test.ts:321-350.

package.json (1)

3-3: package version bump is consistent.

line 3 sets the package version to 1.2.4, which matches the release patch scope. ref: test/unified-settings.test.ts:321-350.

test/unified-settings.test.ts (1)

321-350: good regression coverage for malformed-primary recovery.

this test is deterministic and validates the intended overwrite behavior when primary unified settings are invalid and no usable backup is available. it fits the recovery hardening scope without adding concurrency or windows fragility. ref: test/unified-settings.test.ts:374-499.

test/index.test.ts (1)

4501-4643: lgtm on the stream failover 429 regression test.

the test now correctly asserts that neither accountManager.recordFailure nor capabilityPolicyStore.recordFailure are called during fallback 429 handling. this aligns with the conditional guard at index.ts:1820-1831 that gates failure recording on policy.recordFailure.

one minor note: you've set up recordFailure in the manager mock (line 4569) and spy on CapabilityPolicyStore.prototype.recordFailure (lines 4525-4528), then assert both weren't called (lines 4640-4641). the coverage is solid for this regression.

test/config-save.test.ts (1)

299-321: good regression coverage for unified settings fallback.

the test seeds invalid json in settings.json (line 303), valid data in standalone config.json (lines 304-308), then asserts the save merges standalone values into the repaired unified settings (lines 316-320). this exercises the isInvalidSettingsRecordError() path at lib/unified-settings.ts:143-155.

one edge case worth considering: you might want a companion test for when both unified and standalone are invalid json to verify the behavior in that scenario. currently this test only covers when standalone is valid.

docs/releases/v1.2.4.md (1)

1-35: docs/README.md already points to v1.2.4.md. lines 26 and 55 both reference releases/v1.2.4.md as the current stable release notes, which aligns with the coding guidelines. no update needed here.

			> Likely an incorrect or invalid review comment.

Comment thread docs/README.md
Comment thread docs/releases/v1.2.4.md Outdated
Comment thread index.ts
Comment thread lib/unified-settings.ts
Comment thread scripts/codex.js
Comment thread test/codex-bin-wrapper.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
test/codex-bin-wrapper.test.ts (1)

539-601: ⚠️ Potential issue | 🟠 Major

this still does not hit the intended rename-retry regression.

scripts/codex.js:26 processes auth.json first, and the global busy counter at scripts/codex.js:27-31 is spent by that file because this fixture mutates auth.json too. by the time accounts.json and .codex-global-state.json are visited, there is no rename backoff left, so this only proves the outer snapshot check at scripts/codex.js:678-680, not renameFileWithRetry() for the mutated files. the detached setTimeout(40) also makes the result timing-dependent. make one mutated file the first retried file, or scope the busy injection per file, and gate the external write on a real barrier instead of a timer.

As per coding guidelines, test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/codex-bin-wrapper.test.ts` around lines 539 - 601, The test is
nondeterministic because the fixture mutates auth.json (which scripts/codex.js
processes first and consumes the global busy retry budget), and the external
mutator uses a setTimeout(40) barrier; to fix, change the fake bin so the
external mutator targets one of the files that triggers renameFileWithRetry()
(e.g., "accounts.json" or ".codex-global-state.json") instead of auth.json,
scope injectShadowCleanupBusyFailures to apply per-file retries (not a global
counter) or adjust injectShadowCleanupBusyFailures(3) so retries remain when the
mutator runs, and replace the detached setTimeout barrier with a deterministic
synchronization (create a sentinel file or use a blocking loop that waits for a
sentinel created by the wrapper before writing) so the external write happens
during the rename retry for the intended file and reliably exercises
renameFileWithRetry().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/unified-settings.test.ts`:
- Around line 398-427: Add a synchronous Vitest that mirrors the async overwrite
test: write invalid JSON into getUnifiedSettingsPath(), call
saveUnifiedPluginConfigSync({ codexMode: true, fetchTimeoutMs: 45000 }) and
saveUnifiedDashboardSettingsSync({ menuShowLastUsed: false, uiThemePreset:
"blue" }), then read and JSON.parse the file and assert pluginConfig and
dashboardDisplaySettings match the expected objects; this ensures the sync path
(saveUnifiedPluginConfigSync / saveUnifiedDashboardSettingsSync and the sync
read logic changed at lib/unified-settings.ts:244-246 and 471-478) correctly
overwrites an invalid primary settings.json when no usable backup exists.

---

Duplicate comments:
In `@test/codex-bin-wrapper.test.ts`:
- Around line 539-601: The test is nondeterministic because the fixture mutates
auth.json (which scripts/codex.js processes first and consumes the global busy
retry budget), and the external mutator uses a setTimeout(40) barrier; to fix,
change the fake bin so the external mutator targets one of the files that
triggers renameFileWithRetry() (e.g., "accounts.json" or
".codex-global-state.json") instead of auth.json, scope
injectShadowCleanupBusyFailures to apply per-file retries (not a global counter)
or adjust injectShadowCleanupBusyFailures(3) so retries remain when the mutator
runs, and replace the detached setTimeout barrier with a deterministic
synchronization (create a sentinel file or use a blocking loop that waits for a
sentinel created by the wrapper before writing) so the external write happens
during the rename retry for the intended file and reliably exercises
renameFileWithRetry().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 922e8773-7ce7-452b-96b1-8deaaac035a6

📥 Commits

Reviewing files that changed from the base of the PR and between 3107259 and 012751c.

📒 Files selected for processing (6)
  • docs/releases/v1.2.4.md
  • lib/unified-settings.ts
  • scripts/codex.js
  • test/codex-bin-wrapper.test.ts
  • test/index.test.ts
  • test/unified-settings.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (3)
lib/**

⚙️ CodeRabbit configuration file

focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.

Files:

  • lib/unified-settings.ts
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/unified-settings.test.ts
  • test/codex-bin-wrapper.test.ts
  • test/index.test.ts
docs/**

⚙️ CodeRabbit configuration file

keep README, SECURITY, and docs consistent with actual CLI flags and workflows. whenever behavior changes, require updated upgrade notes and mention new npm scripts.

Files:

  • docs/releases/v1.2.4.md
🔇 Additional comments (3)
test/index.test.ts (2)

4503-4642: good 429 failover regression coverage.

this validates the non-penalty path clearly: no account failure or capability failure is recorded on fallback 429, and persistence behavior stays bounded in test/index.test.ts:4503-4642.


4646-4779: strong non-429 fallback regression.

this new case is precise and useful. it verifies exactly-once failure accounting for both layers and checks no rate-limit persistence side effect in test/index.test.ts:4646-4779.

docs/releases/v1.2.4.md (1)

1-35: release note scope is consistent with the patch.

the page captures the key behavior changes and updated validation totals, and it tracks the fallback capability-policy adjustment covered in test/index.test.ts:4501-4779.

Comment thread scripts/codex.js
Comment thread test/unified-settings.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/codex-bin-wrapper.test.ts`:
- Around line 549-611: The test is timing-sensitive: the detached mutator in the
fake Codex bin (the spawn calling process.execPath with the inline mutateScript
that uses setTimeout(40)) can fire too early or too late relative to the retry
backoff windows (SHADOW_HOME_CLEANUP_BACKOFF_MS) and cause flakes; fix by making
the mutator deterministic instead of using a fixed 40ms delay — either increase
retry attempts (bump injectShadowCleanupBusyFailures(3) to a larger number) or,
preferably, change the mutateScript spawn logic to poll for a marker file
written by the wrapper before the second retry (have the wrapper create the
marker immediately before the second retry and have the mutator wait/poll for
that marker rather than setTimeout), referencing the mutateScript/setTimeout
block and injectShadowCleanupBusyFailures to locate the code to change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 003ab0e7-75dd-420a-9d8a-28f903aef6ff

📥 Commits

Reviewing files that changed from the base of the PR and between 012751c and b141799.

📒 Files selected for processing (3)
  • scripts/codex.js
  • test/codex-bin-wrapper.test.ts
  • test/unified-settings.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (1)
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/codex-bin-wrapper.test.ts
  • test/unified-settings.test.ts
🔇 Additional comments (13)
scripts/codex.js (6)

31-34: lgtm, mirrors the existing cleanup counter pattern.

the new preflight read counter at scripts/codex.js:31-34 follows the same env-injection pattern as the cleanup counter and is properly parsed with a fallback default of 0.


231-247: extraction of simulation helpers looks clean.

maybeThrowSimulatedShadowHomeBusyError() at scripts/codex.js:231-238 and maybeThrowSimulatedShadowHomePreflightReadBusyError() at scripts/codex.js:240-247 are consistent and decrement their respective counters atomically before throwing. no issues.


249-283: destination drift detection now happens before each retry.

ensureShadowHomeDestinationMatchesSnapshot at scripts/codex.js:249-261 with rethrowRetryableReadErrors: true ensures transient destination locks bubble up as retryable errors rather than false EEXIST mismatches. the retry loop at scripts/codex.js:263-283 re-validates the snapshot on every attempt, which closes the delayed-clobber window flagged in earlier reviews.


544-561: preflight read errors now propagate when requested.

at scripts/codex.js:549-551, simulated busy errors fire only when rethrowRetryableReadErrors is true. lines 557-559 rethrow real retryable errors instead of swallowing them into { unreadable: true }, which allows the caller to retry the entire rename cycle rather than treating a locked-but-unchanged file as a snapshot mismatch.


572-584: sync-back now uses the retry-enabled rename.

syncShadowHomeStateFile at scripts/codex.js:572-593 delegates to renameFileWithRetry with the expected destination snapshot, enabling both transient-lock retries and drift detection during shadow-home sync-back.


706-706: call site correctly forwards the original snapshot.

line 706 passes originalSnapshot captured before the shadow run, enabling renameFileWithRetry to detect external mutations between the codex invocation and cleanup.

test/codex-bin-wrapper.test.ts (3)

97-105: helper follows existing injection pattern.

injectShadowPreflightReadBusyFailures at test/codex-bin-wrapper.test.ts:97-105 mirrors injectShadowCleanupBusyFailures and returns the expected env shape.


539-541: good: existing test now exercises the retry path.

adding ...injectShadowCleanupBusyFailures() at test/codex-bin-wrapper.test.ts:539 ensures the "does not clobber original auth state" test also covers the retry/backoff logic.


613-652: deterministic preflight retry coverage looks solid.

the test at test/codex-bin-wrapper.test.ts:613-652 injects both cleanup and preflight read failures without timing dependencies and verifies the final state matches the shadow values. this directly covers the code path at scripts/codex.js:549-559.

test/unified-settings.test.ts (4)

149-189: sync backup error propagation test looks correct.

at test/unified-settings.test.ts:149-189, the test mocks readFileSync via vi.doMock to throw EBUSY when the backup path is read. this covers the sync path at lib/unified-settings.ts:240 where backup read errors propagate. the finally block properly unmocks and resets modules.


191-224: async backup error propagation test is valid.

at test/unified-settings.test.ts:204-211, the spy throws synchronously inside the mock implementation. vitest wraps this so the returned promise rejects with the thrown error, which is correct for testing the async path at lib/unified-settings.ts:277. the assertion at line 220 expects { code: "EPERM" }, matching the thrown error.


398-427: async overwrite test verifies both sections after invalid primary.

the test at test/unified-settings.test.ts:398-427 writes invalid json to the primary, then saves plugin and dashboard settings via the async path, and asserts both sections are present in the resulting file. this covers the recovery-write logic at lib/unified-settings.ts:244-246.


429-453: sync overwrite regression test addresses past review.

the test at test/unified-settings.test.ts:429-453 exercises saveUnifiedPluginConfigSync with an invalid primary and no backup, verifying the sync path at lib/unified-settings.ts:471-478 correctly overwrites the malformed file. this directly addresses the past review comment asking for sync coverage.

Comment thread test/codex-bin-wrapper.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/storage/flagged-storage-io.ts`:
- Around line 79-81: The backup and legacy reads (the backupContent read at
backupPath and the legacy read block) were moved onto readFileWithRetry but the
EBUSY/windows-lock branch isn’t being exercised; fix by ensuring those reads use
the same Windows-lock/EBUSY and 429 retry contract as the primary path: either
call readFileWithRetry with the options that enable EBUSY handling or wrap the
read in a try/catch that checks err.code === 'EBUSY' (and 429 semantics) and
performs the same exponential backoff/retry logic as the primary read; update
the logic around backupContent and the legacy read to explicitly detect and
retry on EBUSY/429 so the windows-lock recovery path is preserved.

In `@test/codex-bin-wrapper.test.ts`:
- Around line 570-576: The inline mutator function waitForMarker contains a dead
`return;` immediately after a `process.exit(0);` (inside the block that writes
accounts.json and .codex-global-state.json); remove the unreachable `return;`
line (or move any needed logic before the `process.exit(0);`) in the
waitForMarker script so the code is no longer confusing and contains no dead
statement.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: d3c08735-81c3-457b-9f56-0160c3622c9b

📥 Commits

Reviewing files that changed from the base of the PR and between b141799 and e0019c4.

📒 Files selected for processing (5)
  • lib/storage/flagged-storage-io.ts
  • lib/unified-settings.ts
  • scripts/codex.js
  • test/codex-bin-wrapper.test.ts
  • test/storage-flagged.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (2)
lib/**

⚙️ CodeRabbit configuration file

focus on auth rotation, windows filesystem IO, and concurrency. verify every change cites affected tests (vitest) and that new queues handle EBUSY/429 scenarios. check for logging that leaks tokens or emails.

Files:

  • lib/storage/flagged-storage-io.ts
  • lib/unified-settings.ts
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/storage-flagged.test.ts
  • test/codex-bin-wrapper.test.ts
🔇 Additional comments (19)
test/codex-bin-wrapper.test.ts (4)

97-105: lgtm, clean helper that mirrors the existing pattern.

sets the independent preflight read counter confirmed at scripts/codex.js:31-34. correctly separated from the cleanup busy counter so both can be combined in tests like lines 659-660.


539-539: correctly adds retry injection to existing clobber test.

this test mutates external state via the fake codex bin (lines 515-517), not during the retry backoff window. no marker dir is needed here since the external change happens before cleanup begins.


549-627: solid regression test for the delayed-clobber race.

marker-based synchronization at test/codex-bin-wrapper.test.ts:551-552,610-611 is deterministic and addresses the earlier flakiness concern. the 5s poll timeout at line 577-579 prevents indefinite hangs on ci. correctly validates that external mutations during backoff are preserved.


629-668: good coverage for preflight read retry path.

directly addresses the regression at scripts/codex.js:571-581 where transient read locks could be misinterpreted as snapshot divergence. combining both helpers at lines 659-660 confirms the counters are independent.

scripts/codex.js (7)

31-36: clean test hook setup with independent counters.

separate counters at scripts/codex.js:27-30 and scripts/codex.js:31-34 allow tests to inject failures into cleanup vs preflight read paths independently.


53-53: lgtm, injection point for testing directory removal retries.


233-268: simulation hooks and marker writing look correct.

decrement-before-throw pattern at lines 234-239 and 243-248 ensures failures are consumed correctly. marker writing at lines 251-268 is best-effort with silent failure, appropriate for test hooks.


270-305: retry loop correctly validates snapshot before each attempt.

ensureShadowHomeDestinationMatchesSnapshot at lines 270-282 throws EEXIST on divergence, which is not in RETRYABLE_SHADOW_HOME_CLEANUP_CODES (line 24), so divergence aborts immediately. transient read locks via rethrowRetryableReadErrors: true at line 275 bubble up as EBUSY which IS retryable. this closes the race window from the past review.


566-584: properly distinguishes transient locks from actual divergence.

when rethrowRetryableReadErrors is true (lines 571-573, 579-581), EBUSY/EPERM from preflight reads bubble up as retryable errors instead of being swallowed into unreadable: true. this prevents the retry loop from aborting on windows file locks.


594-606: threads expected state through to enable per-attempt validation.

expectedDestinationState at line 597 flows to renameFileWithRetry at line 606, enabling the snapshot check before each rename attempt.


728-728: correctly passes pre-operation snapshot for validation.

originalSnapshot from line 720 is captured before shadow operations begin, so any external changes during shadow lifetime will be detected by the per-attempt validation.

lib/unified-settings.ts (3)

56-58: good move to typed invalid-record errors.

lib/unified-settings.ts:56-58, lib/unified-settings.ts:63-65, and lib/unified-settings.ts:162-167 cleanly separate invalid payloads from io failures, which makes fallback behavior deterministic and safer on windows file-lock paths.

Also applies to: 63-65, 162-167


113-117: backup reads now fail closed on locked/unreadable files.

lib/unified-settings.ts:113-117 and lib/unified-settings.ts:130-134 correctly stop collapsing non-invalid backup failures to null. this avoids silent rebuild-from-{} when backup access fails with lock/permission errors.

Also applies to: 130-134


247-249: test coverage for these recovery branches is already present and explicitly tests both scenarios.

lib/unified-settings.ts:247-249 and 284-286 add the "invalid primary + missing/invalid backup" → { record: null, usedBackup: false } behavior. this is directly covered by test/unified-settings.test.ts:74 ("returns null sections when both primary and backup settings files are invalid"), which tests both the sync path (loadUnifiedPluginConfigSync) and async path (loadUnifiedDashboardSettings) when primary and backup are both invalid json.

the "invalid primary + backup EBUSY/EPERM" → propagates (does not downgrade to null) behavior is explicitly tested:

  • test/unified-settings.test.ts:149 ("rethrows sync backup read errors when the primary settings file is invalid") mocks backup readFileSync to throw EBUSY and verifies the exception propagates
  • test/unified-settings.test.ts:191 ("rethrows async backup read errors when the primary settings file is invalid") mocks backup readFile to throw EPERM and verifies the exception propagates

both sync and async paths handle windows-style EBUSY and EPERM correctly. no token/email leaks in these recovery branches.

lib/storage/flagged-storage-io.ts (2)

103-109: good fix on delaying the success log.

lib/storage/flagged-storage-io.ts:103-109 now returns the recovered snapshot without emitting the recovery-success log when persistence fails, and test/storage-flagged.test.ts:720-787 pins that branch.


4-4: good reuse of the retry helper on the primary read path.

lib/storage/flagged-storage-io.ts:4 and lib/storage/flagged-storage-io.ts:129-132 keep the primary load on the same ebusy/eagain contract as lib/storage/flagged-storage-file.ts:8-26. test/storage-flagged.test.ts:344-399 and test/storage-flagged.test.ts:632-682 cover both the integration path and the helper budget.

Also applies to: 129-132

test/storage-flagged.test.ts (3)

336-342: good separation of the non-retryable fallback case.

test/storage-flagged.test.ts:336-342 keeps the eperm fallback behavior covered for lib/storage/flagged-storage-io.ts:142-150, which makes the new retryable-path regression below easier to reason about.


344-399: good deterministic windows-read retry regression.

test/storage-flagged.test.ts:344-399 deterministically reproduces a single ebusy on the primary file and proves we stay on the retried primary path instead of reviving .bak. that matches lib/storage/flagged-storage-io.ts:129-150 and lib/storage/flagged-storage-file.ts:8-26.

As per coding guidelines, test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.


720-787: good regression for failed backup-persist logging.

test/storage-flagged.test.ts:720-787 is deterministic, uses vitest, and locks down the branch in lib/storage/flagged-storage-io.ts:95-117 where recovery still returns data but suppresses the success log after persistence fails.

As per coding guidelines, test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Comment thread lib/storage/flagged-storage-io.ts
Comment thread test/codex-bin-wrapper.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@test/storage-flagged.test.ts`:
- Around line 789-873: The fs.readFile spy (readSpy) is only restored on the
success path which can leak into other tests; declare the spy outside the try
and ensure you call readSpy.mockRestore() (or if defined, restore the spy) in
the finally block so it always runs even on assertion failures—apply the same
change for the other occurrence in this test file that sets up a readFile spy;
keep the rest of the test logic (loadFlaggedAccountsState invocation,
persistRecoveredBackup, logInfo/logError checks, and removeWithRetry) unchanged.
- Around line 720-787: Add a test exercising the case where
persistRecoveredBackup resolves to false: call loadFlaggedAccountsState with a
.bak file present and pass persistRecoveredBackup as an async function that
returns false (rather than throwing), then assert the returned recovered data is
still returned, that logError is called with the same "Failed to persist
recovered flagged account storage" payload including from/to, and that logInfo
is not called; target the persistRecoveredBackup branch in flagged-storage-io
(referencing persistRecoveredBackup and loadFlaggedAccountsState) so the
regression for the "returns false" path is pinned.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 00bf7236-9d3a-4bf0-b54b-98a057967b63

📥 Commits

Reviewing files that changed from the base of the PR and between e0019c4 and 9e65040.

📒 Files selected for processing (2)
  • test/codex-bin-wrapper.test.ts
  • test/storage-flagged.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Greptile Review
🧰 Additional context used
📓 Path-based instructions (1)
test/**

⚙️ CodeRabbit configuration file

tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior. reject changes that mock real secrets or skip assertions.

Files:

  • test/codex-bin-wrapper.test.ts
  • test/storage-flagged.test.ts
🔇 Additional comments (6)
test/codex-bin-wrapper.test.ts (4)

97-105: good helper extraction for deterministic preflight lock injection.

this keeps retry-failure setup explicit and reusable across wrapper regression tests. refs: test/codex-bin-wrapper.test.ts:97-105.
as per coding guidelines, test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior.


539-539: good call adding cleanup-busy injection to the existing clobber regression case.

this forces the retry path instead of only the fast path, so the auth-state guard gets exercised under contention. refs: test/codex-bin-wrapper.test.ts:504-547, test/codex-bin-wrapper.test.ts:539.
as per coding guidelines, test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior.


549-625: strong regression coverage for delayed external mutation during rename backoff.

marker-gated mutation plus retry injection makes this race reproduction deterministic and validates non-clobber behavior for sync-back files. refs: test/codex-bin-wrapper.test.ts:549-625.
as per coding guidelines, test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior.


627-666: solid transient-lock preflight-read retry test.

this directly validates the retry path for busy destination reads and protects cross-platform filesystem lock behavior. refs: test/codex-bin-wrapper.test.ts:627-666.
as per coding guidelines, test/**: tests must stay deterministic and use vitest. demand regression cases that reproduce concurrency bugs, token refresh races, and windows filesystem behavior.

test/storage-flagged.test.ts (2)

336-342: good backup-recovery assertion update.

this assertion set at test/storage-flagged.test.ts:336-342 (Line 336 onward) correctly validates fallback behavior when primary reads fail and backup data is used.


344-399: good windows lock retry regression coverage.

the case at test/storage-flagged.test.ts:344-399 (Line 344 onward) is a solid deterministic check for one transient EBUSY on primary read with no backup fallback, consistent with retry behavior in lib/storage/flagged-storage-file.ts:1-28.

Comment thread test/storage-flagged.test.ts
Comment thread test/storage-flagged.test.ts
@ndycode
ndycode merged commit 688802a into main Apr 5, 2026
2 checks passed
@ndycode
ndycode deleted the release/post-merge-review-fixes-1.2.4 branch April 5, 2026 13:21
ndycode added a commit that referenced this pull request Apr 6, 2026
…1.2.4

release: patch post-merge review fixes for v1.2.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant